﻿using Moki;
using Moki.Tests.Model;
using NUnit.Framework;

namespace Moki.Specification
{
    [TestFixture]
    public class PropertiesSpec
    {
        [TearDown]
        public void TearDown()
        {
            Mock.CleanUp();
        }

        [Test]
        public void Should_stub_property_by_set()
        {
            ITests test = Mock.Create<ITests>();

            test.Some = "Some";
            test.Any = "Any";

            Assert.AreEqual("Some", test.Some);
            Assert.AreEqual("Any", test.Any);
        }

        [Test]
        public void Should_stub_property_by_set_on_partial_mock()
        {
            PartialMockTest test = Mock.Create<PartialMockTest>();

            test.IdVirtual = 1;
            test.NameVirtual = "Name";

            Assert.AreEqual(1, test.IdVirtual);
            Assert.AreEqual( "Name", test.NameVirtual);
        }

        [Test]
        public void Should_stub_property_by_set_multiple_times()
        {
            ITests test = Mock.Create<ITests>();

            test.Some = "Some";
             Assert.AreEqual("Some", test.Some);
            test.Some = "Some1";
            Assert.AreEqual("Some1", test.Some);
            test.Some = "Some2";
            Assert.AreEqual("Some2", test.Some);

        }

        [Test]
        public void Should_stub_property_get_for_ref_types()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenGet(() => test.Some).Returns("Some");
            Mock.WhenGet(() => test.Any).Returns("Any");

            Assert.AreEqual("Some", test.Some);
            Assert.AreEqual("Any", test.Any);
        }

        [Test]
        public void Should_stub_property_for_value_types()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenGet(() => test.Id).Returns(1);

            Assert.AreEqual(1, test.Id);
        }

        [Test]
        public void Should_callback_after_property_set()
        {
            ITests test = Mock.Create<ITests>();
            int i=0;

            Mock.WhenSet(() => test.Id, 1).Callback(() => i++);

            test.Id = 1;
            test.Id = 2;
            test.Id = 1;
            test.Id = 3;

            Assert.AreEqual(2,i);
        }

        [Test]
        public void Should_callback_after_any_property_set()
        {
            ITests test = Mock.Create<ITests>();
            int i = 0;

            Mock.WhenSet(() => test.Id).Callback(() => i++);

            test.Id = 1;
            test.Id = 2;
            test.Id = 1;
            test.Id = 3;

            Assert.AreEqual(4, i);
        }

        [Test]
        public void When_set_should_not_stub_return_value()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenSet(() => test.Any, "Any");

            Assert.AreNotEqual("Any", test.Any);
        }

        [Test]
        public void Should_stub_inner_property_get()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenGet(() => test.Foo.Bar.BarProperty).Returns("Some");

            Assert.AreEqual("Some", test.Foo.Bar.BarProperty);
        }

        [Test]
        public void Should_callback_after_inner_property_set()
        {
            ITests test = Mock.Create<ITests>();
            int i = 0;

            Mock.WhenSet(() => test.Foo.Bar.BarProperty, "bar").Callback(() => i++);

            test.Foo.Bar.BarProperty = "not bar";

            Assert.AreEqual(0, i);

            test.Foo.Bar.BarProperty = "bar";

            Assert.AreEqual(1, i);
        }

        [Test]
        public void Should_set_property_in_callback()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.DoSomething()).
                Callback(() => test.Some = "Some");

            test.DoSomething();

            Assert.AreEqual("Some", test.Some);
        }

        [Test]
        public void Should_set_property_in_callback_on_partial_mock()
        {
            PartialMockTest test = Mock.Create<PartialMockTest>();

            Mock.WhenCalled(() => test.Do()).
                Callback(() => test.NameVirtual = "Name");

            test.Do();

            Assert.AreEqual("Name", test.NameVirtual);
        }

        [Test]
        public void Should_set_property_in_callback_after_return()
        {
            ITests test = Mock.Create<ITests>();

            Mock.WhenCalled(() => test.GetAnswer()).
                Returns(true).
                Callback(() => test.Some = "Some");

            Assert.AreNotEqual("Some", test.Some);
            test.GetAnswer();
            Assert.AreEqual("Some", test.Some);
        }

        [Test]
        public void Should_set_property_in_callback_after_return_on_partial_mock()
        {
            PartialMockTest test = Mock.Create<PartialMockTest>();

            Mock.WhenCalled(() => test.GetSomething()).
                Returns("test1").
                Callback(() => test.NameVirtual = "Name");

            Assert.AreNotEqual("Name", test.NameVirtual);
            
            test.GetSomething();

            Assert.AreEqual("Name", test.NameVirtual);
        }

    }
}
